/*
 *  Copyright (C) 2004 Cidero, Inc.
 *
 *  Permission is hereby granted to any person obtaining a copy of 
 *  this software to use, copy, modify, merge, publish, and distribute
 *  the software for any non-commercial purpose, subject to the
 *  following conditions:
 *  
 *  The above copyright notice and this permission notice shall be included
 *  in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY IN CONNECTION WITH THE SOFTWARE.
 * 
 *  File: $RCSfile: NetUtil.java,v $
 *
 */
package com.cidero.util;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.NetworkInterface;
import java.net.URL;
import java.util.Enumeration;

import org.cybergarage.net.HostInterface;


/**
 * 
 *  
 */
public class NetUtil
{
  static String defaultLocalIPAddr = null;

  public static String getHostName( String ipAddress )
  {
    String hostname = null;
    try
    {
      InetAddress addr = InetAddress.getByName(ipAddress);
      String host = addr.getHostName();
      hostname = addr.getCanonicalHostName();
    }
    catch( UnknownHostException e )
    {
      System.out.println( "getHostName: Unknown host (" + ipAddress + ")" );
    }
    return hostname;
  }

  public static String getIpAddress( String hostname )
  {
    String ipAddress = null;
    try
    {
      InetAddress addr = InetAddress.getByName( hostname );
      byte[] ipAddr = addr.getAddress();
      ipAddress = "";
      for (int i = 0; i < ipAddr.length; i++)
      {
        if( i > 0 )
          ipAddress += ".";

        ipAddress += ipAddr[i] & 0xFF;
      }
    }
    catch( UnknownHostException e )
    {
      System.out.println( "getIpAddress: Unknown host (" + hostname + ")" );
    }
    return ipAddress;
  }

  public static String getLocalHostName()
  {
    String hostname = null;
    try
    {
      InetAddress addr = InetAddress.getLocalHost();
      byte[] ipAddr = addr.getAddress();
      hostname = addr.getHostName();
    }
    catch( UnknownHostException e )
    {
      System.out.println( "getLocalHostName: error" + e );
    }
    return hostname;
  }

  /**
   *  Get 1st LAN card address for local host, if it exists, or fall
   *  back to 127.0.0.1
   */
  public static String getDefaultLocalIPAddress()
  {
    /* Only do the actual resolution once and save the result for
     * efficiency
     */
    if( defaultLocalIPAddr == null )
    {
      int nAddr = HostInterface.getNHostAddresses();

      if( nAddr > 0 )
        defaultLocalIPAddr = HostInterface.getHostAddress(0);
      else
        defaultLocalIPAddr = getIpAddress( getLocalHostName() );
    }
    return defaultLocalIPAddr;
  }
  

  /**
   *  Check if the address X.X.X.X address matches one of the local interfaces
   */
  public static boolean isLocalAddr( String addr )
  {
		try
    {
			Enumeration nis = NetworkInterface.getNetworkInterfaces();

			while( nis.hasMoreElements() )
      {
				NetworkInterface ni = (NetworkInterface)nis.nextElement();
				Enumeration addrs = ni.getInetAddresses();

				while( addrs.hasMoreElements() )
        {
					InetAddress inetAddr = (InetAddress)addrs.nextElement();
					String localHostAddr = inetAddr.getHostAddress().trim();

          //System.out.println("Testing addr " + addr + " against local " +
          //                             localHostAddr );

          if( localHostAddr.equals( addr.trim() ) )
              return true;
				}
			}
		}
		catch(Exception e)
    {
      System.out.println("Exception: " + e );
      return false;
    }
    
    return false;
  }


  /**
   *  Check if the address X.X.X.X address matches one of the local interfaces
   */
  public static String findInterfaceAddrOnSameSubnetAs( String hostAddr )
  {
		try
    {
			Enumeration nis = NetworkInterface.getNetworkInterfaces();

			while( nis.hasMoreElements() )
      {
				NetworkInterface ni = (NetworkInterface)nis.nextElement();
				Enumeration addrs = ni.getInetAddresses();

				while( addrs.hasMoreElements() )
        {
					InetAddress inetAddr = (InetAddress)addrs.nextElement();
					String localHostAddr = inetAddr.getHostAddress().trim();

          if( onSameSubnet( localHostAddr, hostAddr ) )
            return localHostAddr;
				}
			}
		}
		catch(Exception e)
    {
      System.out.println("Exception: " + e );
      return null;
    }
    
    return null;
  }



  /**
   *  Check if dot-separated net addresses are on the same subnet
   *
   *  @return true if addresses on the same subnet, otherwise false
   */
  public static boolean onSameSubnet( String addr1, String addr2 )
  {
    int addr1Index = addr1.lastIndexOf('.');
    int addr2Index = addr2.lastIndexOf('.');
    if( (addr1Index <= 0) || (addr2Index <= 0) )
      return false;
    
    String addr1Subnet = addr1.substring(0, addr1Index);
    String addr2Subnet = addr2.substring(0, addr2Index);
    
    if( addr1Subnet.equals( addr2Subnet ) )
      return true;

    return false;
  }

  
  public static void main( String args[] )
  {
    System.out.println("Local host name: " + getLocalHostName() );
    System.out.println("Local host addr: " + 
                       getIpAddress( getLocalHostName() ) );
    System.out.println("Local host default external addr: " + 
                       getDefaultLocalIPAddress() );
    
    System.out.println("hostname for '192.168.2.100': " + 
                       getHostName( "192.168.2.100" ) );

    try
    {
      /*
      if( args.length > 0 )
      {
        URL url = new URL(args[0]);

        System.out.println("URL host = " + url.getHost() );

        String addr = url.getHost();
      
        if( isLocalAddr( addr ) )
        {
          System.out.println("Addr '" + args[0] + "' is local" );
        }
        else
        {
          System.out.println("Addr '" + args[0] + "' is NOT local" );
        }
      }
      */

      if( args.length > 1 )
      {
        if( onSameSubnet( args[0], args[1] ) )
        {
          System.out.println("Addrs " + args[0] + " " + args[1] +
                             " on same subnet" );
        }
        else
        {
          System.out.println("Addrs " + args[0] + " " + args[1] +
                             " NOT on same subnet" );
        }

        System.out.println("Local host interface for addr " + args[0] +
                           " " + findInterfaceAddrOnSameSubnetAs( args[0] ) );
        System.out.println("Local host interface for addr " + args[1] +
                           " " + findInterfaceAddrOnSameSubnetAs( args[1] ) );

      }
    }
    catch( Exception e )
    {
      System.out.println("Exception: " + e );
    }
    
  }
  
}
